package com.ytq.pratice.servlet;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.concurrent.ConcurrentHashMap;

import com.ytq.pratice.demo.mvc.action.DemoAction;
import com.ytq.pratice.servlet.spring.annotation.Autowired;
import com.ytq.pratice.servlet.spring.annotation.Controller;
import com.ytq.pratice.servlet.spring.annotation.Service;


/**
 * @author yuantongqin
 * @date 2018/9/25 下午5:06
 */
public class DispatchServlet extends HttpServlet {

    Properties contextConfig = new Properties();
    List<String> className = new ArrayList<>();

    Map<String, Object> beandefinition = new ConcurrentHashMap<>();

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        this.doPost(req, resp);
    }

    @Override
    protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        super.doPost(req, resp);

    }

    @Override
    public void init(ServletConfig config) throws ServletException {
        super.init(config);

        //定位
        String location = config.getInitParameter("contextConfigLocation");
        doLocationConfig(location);

        //加载
        doScanner(contextConfig.getProperty("scanner"));

        //注册
        doRegister();

        //依赖注入,在spring中，调用getBean方法才出发依赖注入
        doAutowried();

        //
        doAction();


    }

    private void doAction() {
        DemoAction demoAction = (DemoAction) beandefinition.get("demoAction");
        demoAction.sayHello("change");

        String name ="";
    }

    private void doAutowried() {
        Iterator<Map.Entry<String, Object>> iterator = beandefinition.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<String, Object> next = iterator.next();
            Object value = next.getValue();
            Field[] fields = value.getClass().getDeclaredFields();
            for (Field field : fields) {
                if (!field.isAnnotationPresent(Autowired.class)) {
                    continue;
                }
                String beanName = field.getAnnotation(Autowired.class).value();
                //如果beanName为空，也就是这个字段没有值，取得是类路径名
                if("".equals(beanName)){
                    beanName = field.getType().getName();
                }
                field.setAccessible(true);
                try {
                    //所以这个如果根据beanName赋值的话，会造成值找不到，因为在beanName中保存的是类名，而field.set
                    // 设置时一般通过接口名设置值；
                    field.set(value,beandefinition.get(beanName));
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }

            }


        }

    }

    private void doRegister() {
        for (String name : className) {
            try {
                Class<?> clazz = Class.forName(name);
                if (clazz.isAnnotationPresent(Controller.class)) {
                    //如果是controller注释的类的就将类初始化，然后保存到map集合中
                    String beanName = lowerBeanName(clazz.getSimpleName());
                    Object cla = clazz.newInstance();
                    beandefinition.put(beanName, cla);
                } else if (clazz.isAnnotationPresent(Service.class)) {
                    //service 一般注册在接口的实现类上

                    Service service = clazz.getAnnotation(Service.class);
                    String beanName = service.value();
                    if ("".equals(beanName)) {
                        beanName = lowerBeanName(clazz.getSimpleName());
                    }
                    Object instance = clazz.newInstance();
                    beandefinition.put(beanName, instance);

                    Class<?>[] interfaces = clazz.getInterfaces();
                    //如果这个类实现了多个接口，
                    for (Class<?> anInterface : interfaces) {
                        beandefinition.put(anInterface.getName(), instance);
                    }
                } else {
                    continue;
                }

            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (InstantiationException e) {
                e.printStackTrace();
            }


        }

    }

    private String lowerBeanName(String beanName) {
        char[] chars = beanName.toCharArray();
        chars[0] += 32;//将第一个字母小写
        return String.valueOf(chars);
    }

    private void doScanner(String packageName) {
        URL url = this.getClass().getClassLoader().getResource("/" + packageName.replaceAll("\\.", "/"));
        File file = new File(url.getFile());
        File[] files = file.listFiles();
        for (File f : files) {
            if (!f.isFile()) {
                doScanner(packageName + "." + f.getName());
            } else {
                String fileName = f.getName().replace(".class", "");
                className.add(packageName + "." + fileName);
            }
        }

    }

    private void doLocationConfig(String location) {
        InputStream resource = null;
        try {
            resource = this.getClass().getClassLoader().getResourceAsStream(location.replace("classpath:", ""));
            contextConfig.load(resource);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (resource != null) {
                try {
                    resource.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }


}
